using System;
using System.Collections.Generic;
using LitJson;
using LocalizationUtils.Prefs;
using IPreferences = LocalizationUtils.Prefs.IPreferences;

namespace LocalizationUtils
{
    public static class SettingManager
    {
        private static readonly string USERNAME_KEY = "Username";
        private static readonly string PASSWORD_KEY = "Password";

        private static string currentUsername = string.Empty;
        private static Setting setting = new Setting();

        private static IPreferences s_prefs;

        public static void Init(string path)
        {
            if (path != null)
            {
                s_prefs = new BinaryFilePreferences(path);
                string temp = s_prefs.GetString("Setting");
                if (!String.IsNullOrEmpty(temp))
                {
                    setting = JsonMapper.ToObject<Setting>(temp);
                }
                else
                {
                    setting = new Setting();
                    Save();
                }
            }
            else
            {
                s_prefs = new BinaryFilePreferences();
                setting = new Setting();
            }
        }

        public static void SetUsername(string username)
        {
            currentUsername = username;
            if (!setting.IsHavePlayerSetting(currentUsername))
            {
                setting.CreateNewPlayer(currentUsername);
            }
        }

        public static void SetPassword(string password)
        {
            SetString(PASSWORD_KEY, password);
        }

        public static string GetUsername()
        {
            return currentUsername;
        }

        public static string GetPassword()
        {
            return GetString(PASSWORD_KEY);
        }

        public static string GetString(string key, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? string.Empty : result;
        }

        public static void SetString(string key, string value, bool isPublic = false)
        {
            if (isPublic)
            {
                setting.publicData[key] = value;
            }
            else
            {
                setting.SetPlayerSettingValue(currentUsername, key, value);
            }

            Save();
        }

        public static int GetInt(string key, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? 0 : int.Parse(result);
        }

        public static int GetInt(string key, bool isPublic = false, int value = 0)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? value : int.Parse(result);
        }

        public static int GetIntOrDefault(string key, int defaultValue, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? defaultValue : int.Parse(result);
        }

        public static void SetInt(string key, int value, bool isPublic = false)
        {
            if (isPublic)
            {
                setting.publicData[key] = value.ToString();
            }
            else
            {
                setting.SetPlayerSettingValue(currentUsername, key, value.ToString());
            }

            Save();
        }

        public static long GetLong(string key, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? 0 : long.Parse(result);
        }

        public static void SetLong(string key, long value, bool isPublic = false)
        {
            if (isPublic)
            {
                setting.publicData[key] = value.ToString();
            }
            else
            {
                setting.SetPlayerSettingValue(currentUsername, key, value.ToString());
            }

            Save();
        }

        public static float GetFloat(string key, bool isPublic = false, float value = 0f)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? value : float.Parse(result);
        }


        public static void SetFloat(string key, float value, bool isPublic = false)
        {
            if (isPublic)
            {
                setting.publicData[key] = value.ToString();
            }
            else
            {
                setting.SetPlayerSettingValue(currentUsername, key, value.ToString());
            }

            Save();
        }

        public static bool GetBool(string key, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? false : bool.Parse(result);
        }

        public static bool GetBoolOrDefault(string key, bool defaultValue, bool isPublic = false)
        {
            string result;
            if (isPublic)
            {
                setting.publicData.TryGetValue(key, out result);
            }
            else
            {
                setting.GetPlayerSettingValue(currentUsername, key, out result);
            }

            return result == null ? defaultValue : bool.Parse(result);
        }

        public static void SetBool(string key, bool value, bool isPublic = false)
        {
            if (isPublic)
            {
                setting.publicData[key] = value.ToString();
            }
            else
            {
                setting.SetPlayerSettingValue(currentUsername, key, value.ToString());
            }

            Save();
        }

        static void Save()
        {
            string temp = JsonMapper.ToJson(setting);
            s_prefs.SetString("Setting", temp);
            s_prefs.Save();
        }
    }

    [Serializable]
    class Setting
    {
        public Dictionary<string, string> publicData = new Dictionary<string, string>();
        public Dictionary<string, PlayerSetting> playerData = new Dictionary<string, PlayerSetting>();

        public bool IsHavePlayerSetting(string username)
        {
            return playerData.ContainsKey(username);
        }

        public void CreateNewPlayer(string username)
        {
            PlayerSetting playerSetting = new PlayerSetting();
            playerData[username] = playerSetting;
        }

        public Dictionary<string, string> GetPlayerSetting(string username)
        {
            return playerData[username].settingDic;
        }

        public void GetPlayerSettingValue(string username, string key, out string result)
        {
            GetPlayerSetting(username).TryGetValue(key, out result);
        }

        public void SetPlayerSettingValue(string username, string key, string value)
        {
            GetPlayerSetting(username)[key] = value;
        }
    }

    [Serializable]
    class PlayerSetting
    {
        public Dictionary<string, string> settingDic = new Dictionary<string, string>();
    }
}